home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / utilitys / ed3_1_1 / part02 / undo.c < prev   
C/C++ Source or Header  |  1991-11-07  |  15KB  |  655 lines

  1. /*
  2.     ed3 functions to maintain the undo/redo buffers
  3.  
  4. 10-17-91 fixed two pernicious bugs (what does that mean?)
  5. 10-16-91 undo and redo will do a full refresh is it involves moving points
  6.          and there aren't too many faces on the screen
  7. 10-03-91 add support for the join points action
  8. 10-02-91 main implementation
  9. 09-25-91 created (10 functions)
  10. */
  11.  
  12. #include "sysnogr.h"
  13.  
  14. int head, tail;        /* action list offsets */
  15. int del_here, add_here, final;    /* operation list offsets */
  16.  
  17.  
  18. /*
  19.     enough_room returns whether an operation requiring the creation of many
  20.     objects    will overflow the action buffer or not.  Should be called by
  21.     potentially large operations as a safety measure.
  22.  
  23.     max_verts is the maximum number of vertices for the polys which
  24.     will be added OR deleted.  A value of 0 is passed if thisis unknown.
  25.     Worst case will be assumed (MAX_EDGES vertices).
  26. */
  27.  
  28. int enough_room(p, f, q, dp, df, dq, mp, max_verts)
  29. index p, f, q;
  30. index dp, df, dq;
  31. index mp;
  32. int max_verts;    /* the maximum vertices that any created/delete poly will have */
  33. {
  34.     long bytes = 0;
  35.  
  36.     /* there's always enough room if undo is turned off */
  37.     if (!flags.undo_active) return 1;
  38.  
  39.     bytes += (p * sizeof(a_add_p));
  40.     bytes += (f * sizeof(a_add_f));
  41.     if (max_verts)
  42.         bytes += (q * (sizeof(a_add_q) - ((MAX_EDGES - max_verts) * sizeof(index))));
  43.     else
  44.         bytes += (q * sizeof(a_add_q));    /* we'll consider the worst case */
  45.  
  46.     bytes += (dp * sizeof(a_del_p));
  47.     bytes += (df * sizeof(a_del_f));
  48.     if (max_verts)
  49.         bytes += (q * (sizeof(a_del_q) - ((MAX_EDGES - max_verts) * sizeof(index))));
  50.     else
  51.         bytes += (q * sizeof(a_del_q));    /* we'll consider the worst case */
  52.  
  53.     bytes += (mp * sizeof(a_move_p));
  54.  
  55.     return (bytes < (action_bufsize - (MAX_ACTION_SIZE * 2)));
  56. }
  57.  
  58.  
  59. void undo()
  60. {
  61.     unsigned short actions;
  62.     unsigned short starting_offset;
  63.     unsigned short offset;
  64.     short act, act2;
  65.     int moved_flag = 0;    /* becomes set if the undo involves and move_point actions */
  66.  
  67.     if (!flags.undo_active) return;
  68.     if (add_here == del_here) return;    /* nothing to undo */
  69.  
  70.     add_here --;
  71.     changes--;
  72.     if (add_here < 0) add_here = operation_bufsize-1;    /* wrap around */
  73.     actions = operation[add_here].actions;
  74.     starting_offset = operation[add_here].offset;
  75.  
  76.     /* undo each of the actions in reverse order */
  77.     for (act = actions-1; act >= 0; act--)
  78.     {
  79.         /* scan forward to find the offset of this (act) action */
  80.         offset = starting_offset;
  81.         for (act2 = 0; act2 < act; act2++)
  82.         {
  83.             offset += size_of_action(offset);
  84.             if ((action_bufsize - offset) < MAX_ACTION_SIZE)    /* wrap around */
  85.                 offset = 0;
  86.         }
  87.         if (*((char *)(action+offset)) == AT_MOVE_P) moved_flag = 1;
  88.         /* now actually undo the action */
  89.         undo_action(offset);
  90.     }
  91.     show_counts();    /* we've probably changed the number of faces etc. */
  92.     if (moved_flag && (faces+polys < REFRESH_LEVEL)) refresh_all();
  93. }
  94.  
  95.  
  96. void undo_action(offset)
  97. unsigned short offset;
  98. {
  99.     a_add_p *aap;
  100.     a_del_p *adp;
  101.     a_add_f *aaf;
  102.     a_del_f *adf;
  103.     a_add_q *aaq;
  104.     a_del_q *adq;
  105.     a_move_p *amp;
  106.     a_join_p *ajp;
  107.     a_del_v *adv;
  108.     a_morph_q *amq;
  109.     index i1;
  110.  
  111.     switch (*((char *)(action+offset)))    /* switch on type */
  112.     {
  113.         case AT_ADD_P:
  114.             aap = (a_add_p *)(action+offset);
  115.             draw_point(points-1, colors.erase);
  116.             points--;        /* it's this simple */
  117.             break;
  118.         case AT_DEL_P:
  119.             adp = (a_del_p *)(action+offset);
  120.             insert_point(adp->number, adp->x, adp->y, adp->z);
  121.             draw_point(adp->number, colors.point);
  122.             break;
  123.         case AT_ADD_F:
  124.             aaf = (a_add_f *)(action+offset);
  125.             del_face(faces-1, 1);    /* silently delete */
  126.             break;
  127.         case AT_DEL_F:
  128.             adf = (a_del_f *)(action+offset);
  129.             insert_face(adf->number, adf->p0, adf->p1, adf->p2, adf->color);
  130.             draw_face_color(adf->number, colors.face);
  131.             break;
  132.         case AT_ADD_Q:
  133.             aaq = (a_add_q *)(action+offset);
  134.             del_poly(polys-1, 1);    /* silently delete */
  135.             break;
  136.         case AT_DEL_Q:
  137.             adq = (a_del_q *)(action+offset);
  138.             insert_poly(adq->number, adq->points, adq->p, adq->color);
  139.             draw_poly_color(adq->number, colors.face);
  140.             break;
  141.         case AT_MOVE_P:
  142.             amp = (a_move_p *)(action+offset);
  143.             i1 = amp->p0;
  144.             draw_point(i1, colors.erase);
  145.             point[i1].x -= amp->dx;
  146.             point[i1].y -= amp->dy;
  147.             point[i1].z -= amp->dz;
  148.             convert_point(i1);
  149.             draw_point(i1, colors.point);
  150.             break;
  151.         case AT_JOIN_P:
  152.             ajp = (a_join_p *)(action+offset);
  153.             for (i1 = 0; i1 < ajp->changes; i1++)
  154.             {
  155.                 change_facet(ajp->p0, ajp->p1, ajp->changed[i1]);
  156.             }
  157.             break;
  158.         case AT_DEL_V:
  159.             adv = (a_del_v *)(action+offset);
  160.             insert_vertex(adv->q, adv->vert, adv->p0, 1);
  161.             break;
  162.         case AT_MORPH_Q:
  163.             amq = (a_morph_q *)(action+offset);
  164.             del_face(faces-1, 1);
  165.             break;
  166.     }
  167. }
  168.  
  169.  
  170. /* change the reference to point p0 in facet i1 to point p1 */
  171.  
  172. void change_facet(p0, p1, i1)
  173. index p0, p1, i1;
  174. {
  175.     short vert;
  176.  
  177.     if (i1 & POLYFLAG)
  178.     {
  179.         i1 &= ~POLYFLAG;    /* turn flag off */
  180.         for (vert = 0; vert < poly[i1].verts; vert++)
  181.             if (poly[i1].p[vert] == p0)
  182.                 poly[i1].p[vert] = p1;
  183.     }
  184.     else
  185.     {
  186.         for (vert = 0; vert < 3; vert++)
  187.             if (face[i1].p[vert] == p0)
  188.                 face[i1].p[vert] = p1;
  189.     }
  190. }
  191.  
  192.  
  193. void redo()
  194. {
  195.     unsigned short actions;
  196.     unsigned short starting_offset;
  197.     unsigned short offset;
  198.     short act;
  199.     int moved_flag = 0;    /* becomes set if the undo involves and move_point actions */
  200.  
  201.     if (!flags.undo_active) return;
  202.     if (add_here == final) return;    /* nothing to redo */
  203.  
  204.     actions = operation[add_here].actions;
  205.     starting_offset = operation[add_here].offset;
  206.  
  207.     /* redo each of the actions in forward order */
  208.     offset = starting_offset;
  209.     for (act = 0; act < actions; act++)
  210.     {
  211.         if (*((char *)(action+offset)) == AT_MOVE_P) moved_flag = 1;
  212.         redo_action(offset);    /* now actually redo the action */
  213.         offset += size_of_action(offset);
  214.     }
  215.     add_here ++;
  216.     changes ++;
  217.     show_counts();    /* we've probably changed the number of faces etc. */
  218.     if (moved_flag && (faces+polys < REFRESH_LEVEL)) refresh_all();
  219. }
  220.  
  221.  
  222. void redo_action(offset)
  223. unsigned short offset;
  224. {
  225.     a_add_p *aap;
  226.     a_del_p *adp;
  227.     a_add_f *aaf;
  228.     a_del_f *adf;
  229.     a_add_q *aaq;
  230.     a_del_q *adq;
  231.     a_move_p *amp;
  232.     a_join_p *ajp;
  233.     a_del_v *adv;
  234.     a_morph_q *amq;
  235.     index i1;
  236.  
  237.     switch (*((char *)(action+offset)))    /* switch on type */
  238.     {
  239.         case AT_ADD_P:
  240.             aap = (a_add_p *)(action+offset);
  241.             add_point0(aap->x, aap->y, aap->z);
  242.             draw_point(points-1, colors.point);
  243.             break;
  244.         case AT_DEL_P:
  245.             adp = (a_del_p *)(action+offset);
  246.             draw_point(adp->number, colors.erase);
  247.             del_point(adp->number, 1, 1);
  248.             break;
  249.         case AT_ADD_F:
  250.             aaf = (a_add_f *)(action+offset);
  251.             add_face0(aaf->p0, aaf->p1, aaf->p2, aaf->color);
  252.             draw_face_color(faces-1, colors.face);
  253.             break;
  254.         case AT_DEL_F:
  255.             adf = (a_del_f *)(action+offset);
  256.             del_face(adf->number, 1);    /* silently delete */
  257.             break;
  258.         case AT_ADD_Q:
  259.             aaq = (a_add_q *)(action+offset);
  260.             add_poly(aaq->points, aaq->color, aaq->p, 1);
  261.             draw_poly_color(polys-1, colors.face);
  262.             break;
  263.         case AT_DEL_Q:
  264.             adq = (a_del_q *)(action+offset);
  265.             del_poly(adq->number, 1);    /* silently delete */
  266.             break;
  267.         case AT_MOVE_P:
  268.             amp = (a_move_p *)(action+offset);
  269.             i1 = amp->p0;
  270.             draw_point(i1, colors.erase);
  271.             point[i1].x += amp->dx;
  272.             point[i1].y += amp->dy;
  273.             point[i1].z += amp->dz;
  274.             convert_point(i1);
  275.             draw_point(i1, colors.point);
  276.             break;
  277.         case AT_JOIN_P:
  278.             ajp = (a_join_p *)(action+offset);
  279.             for (i1 = 0; i1 < ajp->changes; i1++)
  280.             {
  281.                 change_facet(ajp->p1, ajp->p0, ajp->changed[i1]);
  282.             }
  283.             break;
  284.         case AT_DEL_V:
  285.             adv = (a_del_v *)(action+offset);
  286.             delete_vertex(adv->q, adv->vert, 1);
  287.             break;
  288.         case AT_MORPH_Q:
  289.             amq = (a_morph_q *)(action+offset);
  290.             poly_to_face(amq->q, 1);
  291.             break;
  292.     }
  293. }
  294.  
  295.  
  296. unsigned short size_of_action(offset)
  297. unsigned short offset;
  298. {
  299.     a_add_q *aaq = (a_add_q *)(action + offset);
  300.     a_del_q *adq = (a_del_q *)(action + offset);
  301.     a_join_p *ajp = (a_join_p *)(action + offset);
  302.  
  303.     switch (*((char *)(action+offset)))    /* switch on type */
  304.     {
  305.         case AT_ADD_P: return sizeof(a_add_p);
  306.         case AT_DEL_P: return sizeof(a_del_p);
  307.         case AT_ADD_F: return sizeof(a_add_f);
  308.         case AT_DEL_F: return sizeof(a_del_f);
  309.         case AT_ADD_Q:
  310.             return (sizeof(a_add_q) -
  311.                 ((MAX_EDGES - aaq->points) * sizeof(index)));
  312.         case AT_DEL_Q:
  313.             return (sizeof(a_del_q) -
  314.                 ((MAX_EDGES - adq->points) * sizeof(index)));
  315.         case AT_MOVE_P: return sizeof(a_move_p);
  316.         case AT_JOIN_P:
  317.             return (sizeof(a_join_p) -
  318.                 ((MAX_EDGES - ajp->changes) * sizeof(index)));
  319.         case AT_DEL_V: return sizeof(a_del_v);
  320.         case AT_MORPH_Q: return sizeof(a_morph_q);
  321.     }
  322. }
  323.  
  324.  
  325. void action_add_p(x, y, z)
  326. coord x, y, z;
  327. {
  328.     a_add_p *new;
  329.  
  330.     if (!flags.undo_active) return;
  331.     make_room();
  332.  
  333.     new = (a_add_p *)(action + head);
  334.     new->type = AT_ADD_P;
  335.     new->x = x;
  336.     new->y = y;
  337.     new->z = z;
  338.  
  339.     head += sizeof(a_add_p);
  340.     operation[add_here].actions++;
  341. }
  342.  
  343.  
  344. void action_del_p(p, x, y, z)
  345. index p;
  346. coord x, y, z;
  347. {
  348.     a_del_p *new;
  349.  
  350.     if (!flags.undo_active) return;
  351.     make_room();
  352.  
  353.     new = (a_del_p *)(action + head);
  354.     new->type = AT_DEL_P;
  355.     new->x = x;
  356.     new->y = y;
  357.     new->z = z;
  358.     new->number = p;
  359.  
  360.     head += sizeof(a_del_p);
  361.     operation[add_here].actions++;
  362. }
  363.  
  364.  
  365. void action_add_f(p0, p1, p2, col)
  366. index p0, p1, p2;
  367. int col;
  368. {
  369.     a_add_f *new;
  370.  
  371.     if (!flags.undo_active) return;
  372.     make_room();
  373.  
  374.     new = (a_add_f *)(action + head);
  375.     new->type = AT_ADD_F;
  376.     new->p0 = p0;
  377.     new->p1 = p1;
  378.     new->p2 = p2;
  379.     new->color = col;
  380.  
  381.     head += sizeof(a_add_f);
  382.     operation[add_here].actions++;
  383. }
  384.  
  385.  
  386. void action_del_f(f)
  387. index f;
  388. {
  389.     a_del_f *new;
  390.  
  391.     if (!flags.undo_active) return;
  392.     make_room();
  393.  
  394.     new = (a_del_f *)(action + head);
  395.     new->type = AT_DEL_F;
  396.     new->color = face[f].color;
  397.     new->p0 = face[f].p[0];
  398.     new->p1 = face[f].p[1];
  399.     new->p2 = face[f].p[2];
  400.     new->number = f;
  401.  
  402.     head += sizeof(a_del_f);
  403.     operation[add_here].actions++;
  404. }
  405.  
  406.  
  407. void action_add_q(points, p, col)
  408. int points;
  409. index *p;
  410. int col;
  411. {
  412.     a_add_q *new;
  413.     int pc;        /* point counter */
  414.     int action_size;
  415.  
  416.     if (!flags.undo_active) return;
  417.     make_room();
  418.  
  419.     new = (a_add_q *)(action + head);
  420.     new->type = AT_ADD_Q;
  421.     new->points = points;
  422.     new->color = col;
  423.     action_size = sizeof(a_add_q) - ((MAX_EDGES-points) * sizeof(index));
  424.     for (pc = 0; pc < points; pc++)
  425.         new->p[pc] = p[pc];
  426.  
  427.     head += action_size;
  428.     operation[add_here].actions++;
  429. }
  430.  
  431.  
  432. void action_del_q(q)
  433. index q;
  434. {
  435.     a_del_q *new;
  436.     int pc;        /* politically correct personal computer point counter */
  437.     int action_size;
  438.     int verts;
  439.  
  440.     if (!flags.undo_active) return;
  441.     make_room();
  442.  
  443.     verts = poly[q].verts;
  444.     new = (a_del_q *)(action + head);
  445.     new->type = AT_DEL_Q;
  446.     new->points = verts;
  447.     new->color = poly[q].color;
  448.     new->number = q;
  449.     action_size = sizeof(a_del_q) - ((MAX_EDGES-verts) * sizeof(index));
  450.     for (pc = 0; pc < verts; pc++)
  451.         new->p[pc] = poly[q].p[pc];
  452.  
  453.     head += action_size;
  454.     operation[add_here].actions++;
  455. }
  456.  
  457.  
  458. void action_move_p(p, dx, dy, dz)
  459. index p;
  460. coord dx, dy, dz;
  461. {
  462.     a_move_p *new;
  463.  
  464.     if (!flags.undo_active) return;
  465.     make_room();
  466.  
  467.     new = (a_move_p *)(action + head);
  468.     new->type = AT_MOVE_P;
  469.     new->p0 = p;
  470.     new->dx = dx;
  471.     new->dy = dy;
  472.     new->dz = dz;
  473.  
  474.     head += sizeof(a_move_p);
  475.     operation[add_here].actions++;
  476. }
  477.  
  478.  
  479. void action_join_p(p0, p1, changed, changes)
  480. index p0, p1;
  481. index *changed;
  482. index changes;
  483. {
  484.     a_join_p *new;
  485.     int action_size;
  486.     short i1;
  487.  
  488.     if (!flags.undo_active) return;
  489.     make_room();
  490.  
  491.     new = (a_join_p *)(action + head);
  492.     new->type = AT_JOIN_P;
  493.     new->p0 = p0;
  494.     new->p1 = p1;
  495.     new->changes = changes;
  496.     for (i1 = 0; i1 < changes; i1++)
  497.         new->changed[i1] = changed[i1];
  498.  
  499.     action_size = sizeof(a_join_p) - ((MAX_EDGES-changes) * sizeof(index));
  500.     head += action_size;
  501.     operation[add_here].actions++;
  502. }
  503.  
  504.  
  505. void action_del_v(q, vert, p0)
  506. index q, p0;
  507. char vert;
  508. {
  509.     a_del_v *new;
  510.  
  511.     if (!flags.undo_active) return;
  512.     make_room();
  513.  
  514.     new = (a_del_v *)(action + head);
  515.     new->type = AT_DEL_V;
  516.     new->q = q;
  517.     new->vert = vert;
  518.     new->p0 = p0;
  519.  
  520.     head += sizeof(a_del_v);
  521.     operation[add_here].actions++;
  522. }
  523.  
  524.  
  525. void action_morph_q(q)
  526. index q;
  527. {
  528.     a_morph_q *new;
  529.  
  530.     if (!flags.undo_active) return;
  531.     make_room();
  532.  
  533.     new = (a_morph_q *)(action + head);
  534.     new->type = AT_MORPH_Q;
  535.     new->q = q;
  536.  
  537.     head += sizeof(a_morph_q);
  538.     operation[add_here].actions++;
  539. }
  540.  
  541.  
  542. void make_room()
  543. {
  544.     int usable;    /* usable room ahead of the insertion (head) point */
  545.     int ok = 0;
  546.  
  547.     if (flags.debug) printf("\tmake_room(%d, %d) ->", tail, head);
  548.  
  549.     while (!ok)
  550.     {
  551.         if (head >= tail)
  552.         {
  553.             usable = action_bufsize - head;
  554.             if (usable <= MAX_ACTION_SIZE)    /* end of buffer */
  555.             {
  556.                 head = 0;    /* wrap around */
  557.                 /* wrapped around onto a full buffer? */
  558.                 if (tail == 0)
  559.                     /* put some space between the offsets */
  560.                     delete_oldest_operation();
  561.             }
  562.             else
  563.                 ok = 1;
  564.         }
  565.         if (head < tail)    /* this is not an else because head can change above */
  566.         {
  567.             usable = tail - head;
  568.             if (usable <= MAX_ACTION_SIZE)    /* not enough room */
  569.                 delete_oldest_operation();    /* make some more room */
  570.             else
  571.                 ok = 1;
  572.         }
  573.     }
  574.     if (flags.debug) printf("(%d, %d)\n", tail, head);
  575. }
  576.  
  577.  
  578. void delete_oldest_operation()
  579. {
  580.     int act = operation[del_here].actions;
  581.     int offset = operation[del_here].offset;
  582.     int ac;
  583.     int size;
  584.  
  585.     if (flags.debug) printf("delete_oldest (%d %d) (add %d del %d) ", tail, head, add_here, del_here);
  586.  
  587.     if (offset != tail)
  588.     {
  589.         if (flags.debug) printf("tail %d, offset of oldest action %d\n", tail, offset);
  590.         sys_exit("bad circular unfo buffer logic");
  591.     }
  592.     for (ac = 0; ac < act; ac++)
  593.     {
  594.         size = size_of_action(offset);
  595.         if (flags.debug) printf(" (deleting %d) ", size);
  596.         tail += size;
  597.         offset += size;
  598.         if ((action_bufsize - tail) < MAX_ACTION_SIZE)
  599.             tail = offset = 0;
  600.     }
  601.     del_here++;
  602.     if (del_here >= operation_bufsize) del_here = 0;    /* wrap around */
  603. }
  604.  
  605.  
  606. /* call at startup or whenever you need to destroy all history
  607.     (like when loading or clearing the entire project) */
  608.  
  609. void init_undo()
  610. {
  611.     head = tail = 0;
  612.     del_here = add_here = 0;
  613.     memset(action, 0, action_bufsize);    /* clear buffer */
  614.     changes = 0;
  615. }
  616.  
  617.  
  618. void begin_operation()
  619. {
  620.     if (!flags.undo_active) return;
  621.     if (flags.debug) printf("begin:(%d, %d)\n", tail, head);
  622.  
  623.     /* maybe the operation buffer is almost full */
  624.     if ((add_here+1)%operation_bufsize == del_here)
  625.         delete_oldest_operation();
  626.  
  627.     if (add_here != final)    /* if we have redone some operations */
  628.     {
  629.         /* they are lost when we begin a new operation */
  630.         final = add_here;
  631.         /* truncate the action list accordingly */
  632.         head = operation[add_here].offset;
  633.     }
  634.     /* make sure that the head offset we have at this point
  635.        is OK before storing it in the operation structure */
  636.     make_room();
  637.     if (flags.debug) printf("offset of action %d is %d\n", add_here, head);
  638.     operation[add_here].offset = head;
  639.     operation[add_here].actions = 0;
  640. }
  641.  
  642.  
  643. void end_operation()
  644. {
  645.     if (!flags.undo_active) return;
  646.     if (flags.debug) printf("end:(%d, %d)\n\n", tail, head);
  647.  
  648.     add_here++;
  649.     changes++;
  650.     if (add_here >= operation_bufsize) add_here = 0;    /* wrap around */
  651.     final = add_here;
  652. }
  653.  
  654.  
  655.